//读Item.Wz
package net.sf.odinms.server;

import java.awt.Point;
import java.io.File;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.LinkedList;

import java.util.TimeZone;
import net.sf.odinms.client.Equip;
import net.sf.odinms.client.IItem;
import net.sf.odinms.client.MapleClient;
import net.sf.odinms.client.MapleInventoryType;
import net.sf.odinms.client.MapleWeaponType;
import net.sf.odinms.client.SkillFactory;
import net.sf.odinms.client.skills.*;
import net.sf.odinms.database.DatabaseConnection;
import net.sf.odinms.net.channel.handler.FishingHandler.MapleFish;
import net.sf.odinms.provider.MapleData;
import net.sf.odinms.provider.MapleDataDirectoryEntry;
import net.sf.odinms.provider.MapleDataFileEntry;
import net.sf.odinms.provider.MapleDataProvider;
import net.sf.odinms.provider.MapleDataProviderFactory;
import net.sf.odinms.provider.MapleDataTool;
import net.sf.odinms.server.constants.InventoryConstants;
import net.sf.odinms.tools.Pair;
import net.sf.odinms.tools.Randomizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 
 * @author Matze
 * 
 * TODO: make faster
 * 
 */
public class MapleItemInformationProvider {

    static Logger log = LoggerFactory.getLogger(MapleItemInformationProvider.class);
    private static MapleItemInformationProvider instance = null;
    protected MapleDataProvider itemData;
    protected MapleDataProvider equipData;
    protected MapleDataProvider stringData;
    protected MapleData cashStringData;
    protected MapleData consumeStringData;
    protected MapleData eqpStringData;
    protected MapleData etcStringData;
    protected MapleData insStringData;
    protected MapleData petStringData;
    protected Map<Integer, MapleInventoryType> inventoryTypeCache = new HashMap<Integer, MapleInventoryType>();
    protected Map<Integer, Short> slotMaxCache = new HashMap<Integer, Short>();
    protected Map<Integer, MapleStatEffect> itemEffects = new HashMap<Integer, MapleStatEffect>();
    protected Map<Integer, Map<String, Integer>> equipStatsCache = new HashMap<Integer, Map<String, Integer>>();
    protected Map<Integer, Equip> equipCache = new HashMap<Integer, Equip>();
    protected Map<Integer, Double> priceCache = new HashMap<Integer, Double>();
    protected Map<Integer, Integer> wholePriceCache = new HashMap<Integer, Integer>();
    protected Map<Integer, Integer> projectileWatkCache = new HashMap<Integer, Integer>();
    protected Map<Integer, String> nameCache = new HashMap<Integer, String>();
    protected Map<Integer, String> descCache = new HashMap<Integer, String>();
    protected Map<Integer, String> msgCache = new HashMap<Integer, String>();
    protected Map<Integer, Boolean> dropRestrictionCache = new HashMap<Integer, Boolean>();
    protected Map<Integer, Boolean> pickupRestrictionCache = new HashMap<Integer, Boolean>();
    protected Map<Integer, Boolean> isQuestItemCache = new HashMap<Integer, Boolean>();
    protected Map<Integer, List<SummonEntry>> summonEntryCache = new HashMap<Integer, List<SummonEntry>>();
    protected List<Pair<Integer, String>> itemNameCache = new ArrayList<Pair<Integer, String>>();
    protected Map<Integer, Integer> getMesoCache = new HashMap<Integer, Integer>();
    protected Map<Integer, Integer> getExpCache = new HashMap<Integer, Integer>();
    protected Map<Integer, String> itemTypeCache = new HashMap<Integer, String>();
    protected Map<Integer, Map<String, String>> getExpCardTimes = new HashMap<Integer, Map<String, String>>();
    protected Map<Integer, Integer> scriptedItemCache = new HashMap<Integer, Integer>();
    protected Map<Integer, Integer> monsterBookID = new HashMap<Integer, Integer>();
    protected Map<Integer, Boolean> consumeOnPickupCache = new HashMap<Integer, Boolean>();
    protected Map<Integer, List<Integer>> scrollRestrictionCache = new HashMap<Integer, List<Integer>>();
    protected Map<Integer, Boolean> karmaCache = new HashMap<Integer, Boolean>();
    protected Map<Integer, List<MapleFish>> fishingCache = new HashMap<Integer, List<MapleFish>>();
    protected Map<Integer, Integer> getItemLevel = new HashMap<Integer, Integer>();
    protected Map<Integer, Integer> getMakeItemMinLevel = new HashMap<Integer, Integer>();
    protected Map<Integer, Integer> getMakeItemMaxLevel = new HashMap<Integer, Integer>();
    //protected Map<Integer, Map<Integer, Integer>> getCrystalId = new HashMap<Integer, Map<Integer, Integer>>();
    protected Map<Integer, Pair<Integer, Integer>> getCrystalId = new HashMap<Integer, Pair<Integer,Integer>>();
    protected List<Integer> getAllCrystalId = new ArrayList<Integer>();
    protected Map<Integer, Pair<Integer, Integer>> getPotentialId = new HashMap<Integer, Pair<Integer,Integer>>();


    protected MapleItemInformationProvider() {
        loadCardIdData();
        itemData = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("net.sf.odinms.wzpath") + "/Item.wz"));
        equipData = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("net.sf.odinms.wzpath") + "/Character.wz"));
        stringData = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("net.sf.odinms.wzpath") + "/String.wz"));
        cashStringData = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("net.sf.odinms.wzpath") + "/String.wz")).getData("Cash.img");
        consumeStringData = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("net.sf.odinms.wzpath") + "/String.wz")).getData("Consume.img");
        eqpStringData = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("net.sf.odinms.wzpath") + "/String.wz")).getData("Eqp.img");
        etcStringData = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("net.sf.odinms.wzpath") + "/String.wz")).getData("Etc.img");
        insStringData = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("net.sf.odinms.wzpath") + "/String.wz")).getData("Ins.img");
        petStringData = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("net.sf.odinms.wzpath") + "/String.wz")).getData("Pet.img");
    }

    public static MapleItemInformationProvider getInstance() {
        if (instance == null) {
            instance = new MapleItemInformationProvider();
        }
        return instance;
    }

    public MapleInventoryType getInventoryType(int itemId) {
        if (inventoryTypeCache.containsKey(itemId)) {
            return inventoryTypeCache.get(itemId);
        }
        MapleInventoryType ret;
        String idStr = "0" + String.valueOf(itemId); //在itemid前面加0 转 string 构成各节点名
        //遍历Item.wz文件夹开始
        MapleDataDirectoryEntry root = itemData.getRoot(); //整个Item.wz文件夹的根目录
        for (MapleDataDirectoryEntry topDir : root.getSubdirectories()) { //Item.wz文件夹里的目录 Cash Consume文件夹等
            for (MapleDataFileEntry iFile : topDir.getFiles()) { //各总img文件 例如0501.img
                if (iFile.getName().equals(idStr.substring(0, 4) + ".img")) {
                    //大目录的名字和物品id前4位一致 例如itemid[05010000]的前四位是[0501]  总的img文件的文件名是0501.img 所以两者相等 
                    ret = MapleInventoryType.getByWZName(topDir.getName()); //通过文件夹的名字获得此物品类型 比如Item.wz\Cash文件夹内的物品返回是[MapleInventoryType.USE]
                    inventoryTypeCache.put(itemId, ret);
                    return ret;
                } else if (iFile.getName().equals(idStr.substring(1) + ".img")) { 
                    //总的img文件名和itemid相等[substring(1) 去掉第一位 即把上面在itemid前面加的0给去掉] 例如Pet文件夹里的文件符合这种情况
                    //宠物的img文件名和itemid相等
                    ret = MapleInventoryType.getByWZName(topDir.getName());
                    inventoryTypeCache.put(itemId, ret);
                    return ret;
                }
            }
        }
        //遍历Item.wz文件夹结束
        
        //遍历Character.wz文件夹开始
        root = equipData.getRoot(); //整个Character.wz文件夹的根目录
        for (MapleDataDirectoryEntry topDir : root.getSubdirectories()) { //Character.wz文件夹里的目录Dragon Android Mechanic文件夹等
            for (MapleDataFileEntry iFile : topDir.getFiles()) {
                if (iFile.getName().equals(idStr + ".img")) {
                    /*
                    if(topDir.getName().equals("Dragon"))
                        ret = MapleInventoryType.Dragon; //龙神装备
                    else if(topDir.getName().equals("Android"))
                        ret = MapleInventoryType.Android; //智能机械人装备
                    else if(topDir.getName().equals("Mechanic"))
                        ret = MapleInventoryType.Mechanic; //机械师装备
                    else
                        */
                    ret = MapleInventoryType.EQUIP;
                    inventoryTypeCache.put(itemId, ret);
                    return ret;
                }
            }
        }
        ret = MapleInventoryType.UNDEFINED;
        inventoryTypeCache.put(itemId, ret);
        return ret;
    }

    public List<Pair<Integer, String>> getAllItems() {
        if (!itemNameCache.isEmpty()) {
            return itemNameCache;
        }
        List<Pair<Integer, String>> itemPairs = new ArrayList<Pair<Integer, String>>();
        MapleData itemsData;

        itemsData = stringData.getData("Cash.img");
        for (MapleData itemFolder : itemsData.getChildren()) {
            int itemId = Integer.parseInt(itemFolder.getName());
            String itemName = MapleDataTool.getString("name", itemFolder, "NO-NAME");
            itemPairs.add(new Pair<Integer, String>(itemId, itemName));
        }

        itemsData = stringData.getData("Consume.img");
        for (MapleData itemFolder : itemsData.getChildren()) {
            int itemId = Integer.parseInt(itemFolder.getName());
            String itemName = MapleDataTool.getString("name", itemFolder, "NO-NAME");
            itemPairs.add(new Pair<Integer, String>(itemId, itemName));
        }

        itemsData = stringData.getData("Eqp.img").getChildByPath("Eqp");
        for (MapleData eqpType : itemsData.getChildren()) {
            for (MapleData itemFolder : eqpType.getChildren()) {
                int itemId = Integer.parseInt(itemFolder.getName());
                String itemName = MapleDataTool.getString("name", itemFolder, "NO-NAME");
                itemPairs.add(new Pair<Integer, String>(itemId, itemName));
            }
        }

        itemsData = stringData.getData("Etc.img").getChildByPath("Etc");
        for (MapleData itemFolder : itemsData.getChildren()) {
            int itemId = Integer.parseInt(itemFolder.getName());
            String itemName = MapleDataTool.getString("name", itemFolder, "NO-NAME");
            itemPairs.add(new Pair<Integer, String>(itemId, itemName));
        }

        itemsData = stringData.getData("Ins.img");
        for (MapleData itemFolder : itemsData.getChildren()) {
            int itemId = Integer.parseInt(itemFolder.getName());
            String itemName = MapleDataTool.getString("name", itemFolder, "NO-NAME");
            itemPairs.add(new Pair<Integer, String>(itemId, itemName));
        }

        itemsData = stringData.getData("Pet.img");
        for (MapleData itemFolder : itemsData.getChildren()) {
            int itemId = Integer.parseInt(itemFolder.getName());
            String itemName = MapleDataTool.getString("name", itemFolder, "NO-NAME");
            itemPairs.add(new Pair<Integer, String>(itemId, itemName));
        }
        itemNameCache.addAll(itemPairs);
        return itemPairs;
    }

    public int getScriptedItemNpc(int itemId) {
        if (scriptedItemCache.containsKey(itemId)) {
            return scriptedItemCache.get(itemId);
        }
        MapleData data = getItemData(itemId);
        int npcId = MapleDataTool.getInt("spec/npc", data, 0);
        scriptedItemCache.put(itemId, npcId);

        return scriptedItemCache.get(itemId);
    }

    public boolean isExpOrDropCardTime(int itemId) {
        Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("Asia/ShangHai"));
        String day = MapleDayInt.getDayInt(cal.get(Calendar.DAY_OF_WEEK));
    //    log.info("" + cal.get(Calendar.HOUR_OF_DAY));
        Map<String, String> times;
        if (getExpCardTimes.containsKey(itemId)) {
            times = getExpCardTimes.get(itemId);
        } else {
            List<MapleData> data = getItemData(itemId).getChildByPath("info").getChildByPath("time").getChildren();
            Map<String, String> hours = new HashMap<String, String>();
            for (MapleData childdata : data) {
                //MON:03-07
                String[] time = MapleDataTool.getString(childdata).split(":");
                hours.put(time[0], time[1]);
            }
            times = hours;
            getExpCardTimes.put(itemId, hours);
            cal.get(Calendar.DAY_OF_WEEK);
        }
        if (times.containsKey(day)) {
            String[] hourspan = times.get(day).split("-");
            int starthour = Integer.parseInt(hourspan[0]);
            int endhour = Integer.parseInt(hourspan[1]);
            if (cal.get(Calendar.HOUR_OF_DAY) >= starthour && cal.get(Calendar.HOUR_OF_DAY) <= endhour) {
                return true;
            }
        }
        return false;
    }

    public static class MapleDayInt {

        public static String getDayInt(int day) {
            if (day == 1) {
                return "SUN";
            } else if (day == 2) {
                return "MON";
            } else if (day == 3) {
                return "TUE";
            } else if (day == 4) {
                return "WED";
            } else if (day == 5) {
                return "THU";
            } else if (day == 6) {
                return "FRI";
            } else if (day == 7) {
                return "SAT";
            }
            return null;
        }
    }

    protected MapleData getStringData(int itemId) {
        String cat = "null";
        MapleData theData;
        if (itemId >= 5010000) {
            theData = cashStringData;
        } else if (itemId >= 2000000 && itemId < 3000000) {
            theData = consumeStringData;
        } else if (itemId >= 1010000 && itemId < 1040000 || itemId >= 1122000 && itemId < 1153000) {
            //添加护肩
            theData = eqpStringData;
            cat = "Accessory";
        } else if (itemId >= 1000000 && itemId < 1010000) {
            theData = eqpStringData;
            cat = "Cap";
        } else if (itemId >= 1102000 && itemId < 1103000) {
            theData = eqpStringData;
            cat = "Cape";
        } else if (itemId >= 1040000 && itemId < 1050000) {
            theData = eqpStringData;
            cat = "Coat";
        } else if (itemId >= 20000 && itemId < 22000) {
            theData = eqpStringData;
            cat = "Face";
        } else if (itemId >= 1080000 && itemId < 1090000) {
            theData = eqpStringData;
            cat = "Glove";
        } else if (itemId >= 30000 && itemId < 32000) {
            theData = eqpStringData;
            cat = "Hair";
        } else if (itemId >= 1050000 && itemId < 1060000) {
            theData = eqpStringData;
            cat = "Longcoat";
        } else if (itemId >= 1060000 && itemId < 1070000) {
            theData = eqpStringData;
            cat = "Pants";
        } else if (itemId >= 1802000 && itemId < 1803000 || itemId >= 1812000 && itemId < 1813000 || itemId == 1822000 || itemId == 1832000) {
            theData = eqpStringData;
            cat = "PetEquip";
        } else if (itemId >= 1112000 && itemId < 1120000) {
            theData = eqpStringData;
            cat = "Ring";
        } else if (itemId >= 1092000 && itemId < 1100000) {
            theData = eqpStringData;
            cat = "Shield";
        } else if (itemId >= 1070000 && itemId < 1080000) {
            theData = eqpStringData;
            cat = "Shoes";
        } else if (itemId >= 1900000 && itemId < 1942000) {
            theData = eqpStringData;
            cat = "Taming";
        } else if (itemId >= 1942000 && itemId < 1982000) { //龙神装备
            theData = eqpStringData;
            cat = "Dragon";
        } else if (itemId >= 1612000 && itemId < 1662000) { //机械师装备
            theData = eqpStringData;
            cat = "Mechanic";
        } else if (itemId >= 1662000 && itemId < 1682000) { //智能机械人装备
            theData = eqpStringData;
            cat = "Android";
        } else if (itemId >= 1300000 && itemId < 1800000) {
            theData = eqpStringData;
            cat = "Weapon";
        } else if (itemId >= 4000000 && itemId < 5000000) {
            theData = etcStringData;
        } else if (itemId >= 3000000 && itemId < 4000000) {
            theData = insStringData;
        } else if (itemId >= 5000000 && itemId < 5010000) {
            theData = petStringData;
        } else {
            return null;
        }
        if (cat.matches("null")) {
            if (theData != etcStringData || itemId == 4280000 || itemId == 4280001) {
                return theData.getChildByPath(String.valueOf(itemId));
            } else {
                return theData.getChildByPath("Etc/" + String.valueOf(itemId));
            }
        } else {
            if (theData == eqpStringData) {
                return theData.getChildByPath("Eqp/" + cat + "/" + itemId);
            } else {
                return theData.getChildByPath(cat + "/" + itemId);
            }
        }
    }

    protected MapleData getItemData(int itemId) {
        MapleData ret = null;
        String idStr = "0" + String.valueOf(itemId);
        MapleDataDirectoryEntry root = itemData.getRoot(); //整个item.wz文件夹里的数据
        for (MapleDataDirectoryEntry topDir : root.getSubdirectories()) {
            // we should have .img files here beginning with the first 4 IID
            for (MapleDataFileEntry iFile : topDir.getFiles()) {
                if (iFile.getName().equals(idStr.substring(0, 4) + ".img")) {
                    ret = itemData.getData(topDir.getName() + "/" + iFile.getName());
                    if (ret == null) {
                        return null;
                    }
                    ret = ret.getChildByPath(idStr);
                    return ret;
                } else if (iFile.getName().equals(idStr.substring(1) + ".img")) {
                    return itemData.getData(topDir.getName() + "/" + iFile.getName());
                }
            }
        }
        root = equipData.getRoot();
        for (MapleDataDirectoryEntry topDir : root.getSubdirectories()) {
            for (MapleDataFileEntry iFile : topDir.getFiles()) {
                if (iFile.getName().equals(idStr + ".img")) {
                    return equipData.getData(topDir.getName() + "/" + iFile.getName());
                }
            }
        }
        return ret;
    }

    public short getSlotMax(MapleClient c, int itemId) {
        if (slotMaxCache.containsKey(itemId)) {
            return slotMaxCache.get(itemId);
        }
        short ret = 0;
        MapleData item = getItemData(itemId);
        if (item != null) {
            MapleData smEntry = item.getChildByPath("info/slotMax");
            if (smEntry == null) {
                if (getInventoryType(itemId).getType() == MapleInventoryType.EQUIP.getType()) {
                    ret = 1;
                } else {
                    ret = 100;
                }
            } else {
                if (isThrowingStar(itemId) || isBullet(itemId) || (MapleDataTool.getInt(smEntry) == 0)) {
                    ret = 1;
                }
                ret = (short) MapleDataTool.getInt(smEntry);
                if (isThrowingStar(itemId)) {
                    ret += c.getPlayer().getSkillLevel(SkillFactory.getSkill(标飞.精准暗器)) * 10;
                } else {
                    ret += c.getPlayer().getSkillLevel(SkillFactory.getSkill(枪手.精准枪)) * 10;
                }

            }
        }
        if (!isThrowingStar(itemId) && !isBullet(itemId)) {
            slotMaxCache.put(itemId, ret);
        }

        return ret;
    }

    public boolean isThrowingStar(int itemId) {
        //是标
        return (itemId >= 2070000 && itemId < 2080000);
    }
    
    public int getMeso(int itemId) {
        if (getMesoCache.containsKey(itemId)) {
            return getMesoCache.get(itemId);
        }
        MapleData item = getItemData(itemId);
        if (item == null) {
            return -1;
        }
        int pEntry = 0;
        MapleData pData = item.getChildByPath("info/meso");
        if (pData == null) {
            return -1;
        }
        pEntry = MapleDataTool.getInt(pData);

        getMesoCache.put(itemId, pEntry);
        return pEntry;
    }

    public int getWholePrice(int itemId) {
        if (wholePriceCache.containsKey(itemId)) {
            return wholePriceCache.get(itemId);
        }
        MapleData item = getItemData(itemId);
        if (item == null) {
            return -1;
        }
        int pEntry = 0;
        MapleData pData = item.getChildByPath("info/price");
        if (pData == null) {
            return -1;
        }
        pEntry = MapleDataTool.getInt(pData);

        wholePriceCache.put(itemId, pEntry);
        return pEntry;
    }

    public String getType(int itemId) {
        if (itemTypeCache.containsKey(itemId)) {
            return itemTypeCache.get(itemId);
        }
        MapleData item = getItemData(itemId);
        if (item == null) {
            return "";
        }
        String pEntry;
        MapleData pData = item.getChildByPath("info/islot");
        if (pData == null) {
            return "";
        }
        pEntry = MapleDataTool.getString(pData);

        itemTypeCache.put(itemId, pEntry);
        return pEntry;
    }

    public double getPrice(int itemId) {
        if (priceCache.containsKey(itemId)) {
            return priceCache.get(itemId);
        }
        MapleData item = getItemData(itemId);
        if (item == null) {
            return -1;
        }
        double pEntry = 0.0;
        MapleData pData = item.getChildByPath("info/unitPrice");
        if (pData != null) {
            try {
                pEntry = MapleDataTool.getDouble(pData);
            } catch (Exception e) {
                pEntry = (double) MapleDataTool.getInt(pData);
            }
        } else {
            pData = item.getChildByPath("info/price");
            if (pData == null) {
                return -1;
            }
            pEntry = (double) MapleDataTool.getInt(pData);
        }

        priceCache.put(itemId, pEntry);
        return pEntry;
    }

    protected Map<String, Integer> getEquipStats(int itemId) {
        if (equipStatsCache.containsKey(itemId)) {
            return equipStatsCache.get(itemId);
        }
        Map<String, Integer> ret = new LinkedHashMap<String, Integer>();
        MapleData item = getItemData(itemId);
        if (item == null) {
            return null;
        }
        MapleData info = item.getChildByPath("info");
        if (info == null) {
            return null;
        }
        for (MapleData data : info.getChildren()) {
            if (data.getName().startsWith("inc")) {
                ret.put(data.getName().substring(3), MapleDataTool.getIntConvert(data));
            }
        }
        ret.put("tuc", MapleDataTool.getInt("tuc", info, 0));
        ret.put("reqLevel", MapleDataTool.getInt("reqLevel", info, 0));
        ret.put("reqJob", MapleDataTool.getInt("reqJob", info, 0));
        ret.put("reqSTR", MapleDataTool.getInt("reqSTR", info, 0));
        ret.put("reqDEX", MapleDataTool.getInt("reqDEX", info, 0));
        ret.put("reqINT", MapleDataTool.getInt("reqINT", info, 0));
        ret.put("reqLUK", MapleDataTool.getInt("reqLUK", info, 0));
        ret.put("cash", MapleDataTool.getInt("cash", info, 0));
        ret.put("cursed", MapleDataTool.getInt("cursed", info, 0));
        ret.put("success", MapleDataTool.getInt("success", info, 0));
        ret.put("durability", MapleDataTool.getInt("durability", info, -1)); //耐久度
        if(info.getChildByPath("level") != null)
            ret.put("skilllevel", 1);
        else
            ret.put("skilllevel", 0);
        equipStatsCache.put(itemId, ret);
        return ret;
    }

    public int getReqLevel(int itemId) {
        final Integer req = getEquipStats(itemId).get("reqLevel");
        return req == null ? 0 : req.intValue();
    }

    public int getReqJob(int itemId) {
        final Integer req = getEquipStats(itemId).get("reqJob");
        return req == null ? 0 : req.intValue();
    }

    public int getReqStr(int itemId) {
        final Integer req = getEquipStats(itemId).get("reqSTR");
        return req == null ? 0 : req.intValue();
    }

    public int getReqDex(int itemId) {
        final Integer req = getEquipStats(itemId).get("reqDEX");
        return req == null ? 0 : req.intValue();
    }

    public int getReqInt(int itemId) {
        final Integer req = getEquipStats(itemId).get("reqINT");
        return req == null ? 0 : req.intValue();
    }

    public int getReqLuk(int itemId) {
        final Integer req = getEquipStats(itemId).get("reqLUK");
        return req == null ? 0 : req.intValue();
    }

    public boolean isCash(int itemId) {
        try{
         final Integer req = getEquipStats(itemId).get("cash");
        if (req == null || req == 0) {
            return false;
        }
         return true;
        }catch (Exception e) {
            log.info("{}",e);
            return false;
        }
    }

    public List<Integer> getScrollReqs(int itemId) {
        if (scrollRestrictionCache.containsKey(itemId)) {
            return scrollRestrictionCache.get(itemId);
        }
        List<Integer> ret = new ArrayList<Integer>();
        MapleData data = getItemData(itemId);
        data = data.getChildByPath("req");
        if (data == null) {
            return ret;
        }
        for (MapleData req : data.getChildren()) {
            ret.add(MapleDataTool.getInt(req));
        }
        return ret;
    }

    public List<SummonEntry> getSummonMobs(int itemId) {
        if (this.summonEntryCache.containsKey(itemId)) {
            return summonEntryCache.get(itemId);
        }
        MapleData data = getItemData(itemId);
        int mobSize = data.getChildByPath("mob").getChildren().size();
        List<SummonEntry> ret = new LinkedList<SummonEntry>();
        for (int x = 0; x < mobSize; x++) {
            ret.add(new SummonEntry(MapleDataTool.getIntConvert("mob/" + x + "/id", data), MapleDataTool.getIntConvert("mob/" + x + "/prob", data)));
        }
        if (ret.isEmpty()) {
            log.warn("Empty summon bag, itemID: {}", itemId);
        }
        summonEntryCache.put(itemId, ret);
        return ret;
    }

    public boolean isWeapon(int itemId) {
        return itemId >= 1302000 && itemId < 1492024;
    }

    public MapleWeaponType getWeaponType(int itemId) {
        int cat = itemId / 10000;
        cat = cat % 100;
        switch (cat) {
            case 30:
                return MapleWeaponType.SWORD1H;
            case 31:
                return MapleWeaponType.AXE1H;
            case 32:
                return MapleWeaponType.BLUNT1H;
            case 33:
                return MapleWeaponType.DAGGER;
            case 37:
                return MapleWeaponType.WAND;
            case 38:
                return MapleWeaponType.STAFF;
            case 40:
                return MapleWeaponType.SWORD2H;
            case 41:
                return MapleWeaponType.AXE2H;
            case 42:
                return MapleWeaponType.BLUNT2H;
            case 43:
                return MapleWeaponType.SPEAR;
            case 44:
                return MapleWeaponType.POLE_ARM;
            case 45:
                return MapleWeaponType.BOW;
            case 46:
                return MapleWeaponType.CROSSBOW;
            case 47:
                return MapleWeaponType.CLAW;
            case 39: // Barefists
            case 48:
                return MapleWeaponType.KNUCKLE;
            case 49:
                return MapleWeaponType.GUN;

        }
        return MapleWeaponType.NOT_A_WEAPON;
    }

    public boolean isShield(int itemId) {
        int cat = itemId / 10000;
        cat = cat % 100;
        return cat == 9;
    }

    public boolean isEquip(int itemId) {
        return itemId / 1000000 == 1;
    }

    public boolean isCleanSlate(int scrollId) {
        switch (scrollId) {
            case 2049000:
            case 2049001:
            case 2049002:
            case 2049003:
                return true;
        }
        return false;
    }
    
    public boolean 不需要判断部位的卷轴(int scrollId) {
        switch (scrollId) {
            //白医
            case 2049000:
            case 2049001:
            case 2049002:
            case 2049003:
            case 2049004: //仙
            case 2049005: //神
            //混沌
            case 2049100:
            case 2049116: //强化
            case 2049117:
                return true;
        }
        return false;
    }
    
    public Equip MakeItem(Equip equip, int scrollId) {
        if (equip instanceof Equip) {
            Equip nEquip = equip;
            Map<String, Integer> stats = this.getEquipStats(scrollId);
                        for (Entry<String, Integer> stat : stats.entrySet()) {
                            if (stat.getKey().equals("STR")) {
                                nEquip.setStr((short) (nEquip.getStr() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("DEX")) {
                                nEquip.setDex((short) (nEquip.getDex() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("INT")) {
                                nEquip.setInt((short) (nEquip.getInt() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("LUK")) {
                                nEquip.setLuk((short) (nEquip.getLuk() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("PAD")) {
                                nEquip.setWatk((short) (nEquip.getWatk() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("PDD")) {
                                nEquip.setWdef((short) (nEquip.getWdef() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("MAD")) {
                                nEquip.setMatk((short) (nEquip.getMatk() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("MDD")) {
                                nEquip.setMdef((short) (nEquip.getMdef() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("ACC")) {
                                nEquip.setAcc((short) (nEquip.getAcc() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("EVA")) {
                                nEquip.setAvoid((short) (nEquip.getAvoid() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("Speed")) {
                                nEquip.setSpeed((short) (nEquip.getSpeed() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("Jump")) {
                                nEquip.setJump((short) (nEquip.getJump() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("MHP")) {
                                nEquip.setHp((short) (nEquip.getHp() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("MMP")) {
                                nEquip.setMp((short) (nEquip.getMp() + stat.getValue().intValue()));
                            }
                        }
            } else {

            }
        return equip;
    }


    public IItem scrollEquipWithId(IItem equip, int scrollId, boolean usingWhiteScroll, boolean checkIfGM) {
        if (equip instanceof Equip) {
            Equip nEquip = (Equip) equip;
            Map<String, Integer> stats = this.getEquipStats(scrollId);
            Map<String, Integer> eqstats = this.getEquipStats(equip.getItemId());
            if ((nEquip.getUpgradeSlots() > 0 || isCleanSlate(scrollId)) && Math.ceil(Math.random() * 100.0) <= stats.get("success") || (checkIfGM == true)) {
                short flag = nEquip.getFlag();
                switch (scrollId) {
                    case 2040727:
                        flag |= InventoryConstants.Items.Flags.SPIKES;
                        nEquip.setFlag((byte) flag);
                        return equip;
                    case 2041058:
                        flag |= InventoryConstants.Items.Flags.COLD;
                        nEquip.setFlag((byte) flag);
                        return equip;
                    case 2049000:
                    case 2049001:
                    case 2049002:
                    case 2049003:
                        if (nEquip.getLevel() + nEquip.getUpgradeSlots() < eqstats.get("tuc")) {
                            byte newSlots = (byte) (nEquip.getUpgradeSlots() + 1);
                            nEquip.setUpgradeSlots(newSlots);
                        }
                        break;
                    case 2049100: //混沌卷轴 60%
                    case 2049101: //骗子树液 100%
                    case 2049102: //冒险岛糖浆 100%
                    case 2049103: //海蓝拖鞋专用卷轴 100%
                    case 2049104: //工作人员装备专用卷轴 100%
                    case 2049112: //企鹅国王的武器卷轴 100%
                    case 2049115: //拉瓦那
                    case 2049116: //强化混沌
                    case 2049117: //混沌卷轴 60%
                        int increase = 1;
                        if (Math.ceil(Math.random() * 100.0) <= 50) {
                            increase = increase * -1;
                        }
                        if (nEquip.getStr() > 0) {
                            short newStat = (short) (nEquip.getStr() + Math.ceil(Math.random() * 5.0) * increase);
                            nEquip.setStr(newStat);
                        }
                        if (nEquip.getDex() > 0) {
                            short newStat = (short) (nEquip.getDex() + Math.ceil(Math.random() * 5.0) * increase);
                            nEquip.setDex(newStat);
                        }
                        if (nEquip.getInt() > 0) {
                            short newStat = (short) (nEquip.getInt() + Math.ceil(Math.random() * 5.0) * increase);
                            nEquip.setInt(newStat);
                        }
                        if (nEquip.getLuk() > 0) {
                            short newStat = (short) (nEquip.getLuk() + Math.ceil(Math.random() * 5.0) * increase);
                            nEquip.setLuk(newStat);
                        }
                        if (nEquip.getWatk() > 0) {
                            short newStat = (short) (nEquip.getWatk() + Math.ceil(Math.random() * 5.0) * increase);
                            nEquip.setWatk(newStat);
                        }
                        if (nEquip.getWdef() > 0) {
                            short newStat = (short) (nEquip.getWdef() + Math.ceil(Math.random() * 5.0) * increase);
                            nEquip.setWdef(newStat);
                        }
                        if (nEquip.getMatk() > 0) {
                            short newStat = (short) (nEquip.getMatk() + Math.ceil(Math.random() * 5.0) * increase);
                            nEquip.setMatk(newStat);
                        }
                        if (nEquip.getMdef() > 0) {
                            short newStat = (short) (nEquip.getMdef() + Math.ceil(Math.random() * 5.0) * increase);
                            nEquip.setMdef(newStat);
                        }
                        if (nEquip.getAcc() > 0) {
                            short newStat = (short) (nEquip.getAcc() + Math.ceil(Math.random() * 5.0) * increase);
                            nEquip.setAcc(newStat);
                        }
                        if (nEquip.getAvoid() > 0) {
                            short newStat = (short) (nEquip.getAvoid() + Math.ceil(Math.random() * 5.0) * increase);
                            nEquip.setAvoid(newStat);
                        }
                        if (nEquip.getSpeed() > 0) {
                            short newStat = (short) (nEquip.getSpeed() + Math.ceil(Math.random() * 5.0) * increase);
                            nEquip.setSpeed(newStat);
                        }
                        if (nEquip.getJump() > 0) {
                            short newStat = (short) (nEquip.getJump() + Math.ceil(Math.random() * 5.0) * increase);
                            nEquip.setJump(newStat);
                        }
                        if (nEquip.getHp() > 0) {
                            short newStat = (short) (nEquip.getHp() + Math.ceil(Math.random() * 5.0) * increase);
                            nEquip.setHp(newStat);
                        }
                        if (nEquip.getMp() > 0) {
                            short newStat = (short) (nEquip.getMp() + Math.ceil(Math.random() * 5.0) * increase);
                            nEquip.setMp(newStat);
                        }
                        break;
                    default:
                        for (Entry<String, Integer> stat : stats.entrySet()) {
                            if (stat.getKey().equals("STR")) {
                                nEquip.setStr((short) (nEquip.getStr() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("DEX")) {
                                nEquip.setDex((short) (nEquip.getDex() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("INT")) {
                                nEquip.setInt((short) (nEquip.getInt() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("LUK")) {
                                nEquip.setLuk((short) (nEquip.getLuk() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("PAD")) {
                                nEquip.setWatk((short) (nEquip.getWatk() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("PDD")) {
                                nEquip.setWdef((short) (nEquip.getWdef() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("MAD")) {
                                nEquip.setMatk((short) (nEquip.getMatk() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("MDD")) {
                                nEquip.setMdef((short) (nEquip.getMdef() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("ACC")) {
                                nEquip.setAcc((short) (nEquip.getAcc() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("EVA")) {
                                nEquip.setAvoid((short) (nEquip.getAvoid() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("Speed")) {
                                nEquip.setSpeed((short) (nEquip.getSpeed() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("Jump")) {
                                nEquip.setJump((short) (nEquip.getJump() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("MHP")) {
                                nEquip.setHp((short) (nEquip.getHp() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("MMP")) {
                                nEquip.setMp((short) (nEquip.getMp() + stat.getValue().intValue()));
                            } else if (stat.getKey().equals("afterImage")) {
                            }
                        }
                        break;
                }
                if (!isCleanSlate(scrollId)) {
                    nEquip.setUpgradeSlots((byte) (nEquip.getUpgradeSlots() - 1));
                    nEquip.setLevel((byte) (nEquip.getLevel() + 1));
                }
            } else {
                if (!usingWhiteScroll && !isCleanSlate(scrollId)) {
                    nEquip.setUpgradeSlots((byte) (nEquip.getUpgradeSlots() - 1));
                }
                if (Math.ceil(1.0 + Math.random() * 100.0) < stats.get("cursed")) {
                    return null;
                }
            }
        }
        return equip;
    }

    public IItem getEquipById(int equipId) {
        Equip nEquip;
        nEquip = new Equip(equipId, (byte) 0);
        nEquip.setQuantity((short) 1);
        Map<String, Integer> stats = this.getEquipStats(equipId);
        if (stats != null) {
            for (Entry<String, Integer> stat : stats.entrySet()) {
                if (stat.getKey().equals("STR")) {
                    nEquip.setStr((short) stat.getValue().intValue());
                } else if (stat.getKey().equals("DEX")) {
                    nEquip.setDex((short) stat.getValue().intValue());
                } else if (stat.getKey().equals("INT")) {
                    nEquip.setInt((short) stat.getValue().intValue());
                } else if (stat.getKey().equals("LUK")) {
                    nEquip.setLuk((short) stat.getValue().intValue());
                } else if (stat.getKey().equals("PAD")) {
                    nEquip.setWatk((short) stat.getValue().intValue());
                } else if (stat.getKey().equals("PDD")) {
                    nEquip.setWdef((short) stat.getValue().intValue());
                } else if (stat.getKey().equals("MAD")) {
                    nEquip.setMatk((short) stat.getValue().intValue());
                } else if (stat.getKey().equals("MDD")) {
                    nEquip.setMdef((short) stat.getValue().intValue());
                } else if (stat.getKey().equals("ACC")) {
                    nEquip.setAcc((short) stat.getValue().intValue());
                } else if (stat.getKey().equals("EVA")) {
                    nEquip.setAvoid((short) stat.getValue().intValue());
                } else if (stat.getKey().equals("Speed")) {
                    nEquip.setSpeed((short) stat.getValue().intValue());
                } else if (stat.getKey().equals("Jump")) {
                    nEquip.setJump((short) stat.getValue().intValue());
                } else if (stat.getKey().equals("MHP")) {
                    nEquip.setHp((short) stat.getValue().intValue());
                } else if (stat.getKey().equals("MMP")) {
                    nEquip.setMp((short) stat.getValue().intValue());
                } else if (stat.getKey().equals("tuc")) {
                    nEquip.setUpgradeSlots((byte) stat.getValue().intValue());
                } else if (isDropRestricted(equipId)) { //设置flag节点
                    short flag = nEquip.getFlag();
                    flag |= InventoryConstants.Items.Flags.UNTRADEABLE; //不可交易
                    nEquip.setFlag(flag);
                //} else if (stat.getKey().equals("afterImage")) {
                } else if (stat.getKey().equals("skilllevel")) {
                    nEquip.setItemLevel((byte) stat.getValue().intValue());
                } else if (stat.getKey().equals("durability")) {
                    nEquip.setDurability(stat.getValue().intValue());
                }
            }
        }
        equipCache.put(equipId, nEquip);
        return nEquip.copy();
    }

    private short getRandStat(short defaultValue, int maxRange) {
        if (defaultValue == 0) {
            return 0;
        }

        // vary no more than ceil of 10% of stat
        int lMaxRange = (int) Math.min(Math.ceil(defaultValue * 0.1), maxRange);
        return (short) ((defaultValue - lMaxRange) + Math.floor(Math.random() * (lMaxRange * 2 + 1)));
    }

    public Equip randomizeStats(Equip equip) {
        equip.setStr(getRandStat(equip.getStr(), 5));
        equip.setDex(getRandStat(equip.getDex(), 5));
        equip.setInt(getRandStat(equip.getInt(), 5));
        equip.setLuk(getRandStat(equip.getLuk(), 5));
        equip.setMatk(getRandStat(equip.getMatk(), 5));
        equip.setWatk(getRandStat(equip.getWatk(), 5));
        equip.setAcc(getRandStat(equip.getAcc(), 5));
        equip.setAvoid(getRandStat(equip.getAvoid(), 5));
        equip.setJump(getRandStat(equip.getJump(), 5));
        equip.setSpeed(getRandStat(equip.getSpeed(), 5));
        equip.setWdef(getRandStat(equip.getWdef(), 10));
        equip.setMdef(getRandStat(equip.getMdef(), 10));
        equip.setHp(getRandStat(equip.getHp(), 10));
        equip.setMp(getRandStat(equip.getMp(), 10));
        if (Math.random() * 100 < 30) {
            equip.setIdentify((byte) 1);
        }
        return equip;
    }

    public MapleStatEffect getItemEffect(int itemId) {
        MapleStatEffect ret = itemEffects.get(Integer.valueOf(itemId));
        if (ret == null) {
            MapleData item = getItemData(itemId);
            if (item == null) {
                return null;
            }
            MapleData spec = item.getChildByPath("spec");
            ret = MapleStatEffect.loadItemEffectFromData(spec, itemId);
            itemEffects.put(Integer.valueOf(itemId), ret);
        }
        return ret;
    }

    public boolean isBullet(int itemId) {
        int id = itemId / 10000;
        if (id == 233) {
            return true;
        } else {
            return false;
        }
    }

    public boolean isRechargable(int itemId) {
        int id = itemId / 10000;
        if (id == 233 || id == 207) {
            return true;
        } else {
            return false;
        }
    }

    public boolean isOverall(int itemId) {
        return itemId >= 1050000 && itemId < 1060000;
    }

    public boolean isPet(int itemId) {
        return itemId >= 5000000 && itemId <= 5000100;
    }

    public boolean isArrowForCrossBow(int itemId) {
        //弩箭
        return itemId >= 2061000 && itemId < 2062000;
    }

    public boolean isArrowForBow(int itemId) {
        //弓箭
        return itemId >= 2060000 && itemId < 2061000;
    }

    public boolean isTwoHanded(int itemId) {
        switch (getWeaponType(itemId)) {
            case AXE2H:
            case BLUNT2H:
            case BOW:
            case CLAW:
            case CROSSBOW:
            case POLE_ARM:
            case SPEAR:
            case SWORD2H:
            case GUN:
            case KNUCKLE:
                return true;
            default:
                return false;
        }
    }

    public boolean isTownScroll(int itemId) {
        return (itemId >= 2030000 && itemId < 2030020);
    }

    public boolean isGun(int itemId) {
        return itemId >= 1492000 && itemId <= 1492024;
    }

    public boolean isWritOfSolomon(int itemId) {
        return (itemId >= 2370000 && itemId <= 2370012);
    }

    public int getExpCache(int itemId) {
        if (this.getExpCache.containsKey(itemId)) {
            return getExpCache.get(itemId);
        }
        MapleData item = getItemData(itemId);
        if (item == null) {
            return 0;
        }
        int pEntry = 0;
        MapleData pData = item.getChildByPath("spec/exp");
        if (pData == null) {
            return 0;
        }
        pEntry = MapleDataTool.getInt(pData);

        getExpCache.put(itemId, pEntry);
        return pEntry;
    }

    public int getWatkForProjectile(int itemId) {
        Integer atk = projectileWatkCache.get(itemId);
        if (atk != null) {
            return atk.intValue();
        }
        MapleData data = getItemData(itemId);
        atk = Integer.valueOf(MapleDataTool.getInt("info/incPAD", data, 0));
        projectileWatkCache.put(itemId, atk);
        return atk.intValue();
    }

    public boolean canScroll(int scrollid, int itemid) {
        int scrollCategoryQualifier = (scrollid / 100) % 100;
        int itemCategoryQualifier = (itemid / 10000) % 100;
        return scrollCategoryQualifier == itemCategoryQualifier;
    }

    public String getName(int itemId) {
        if (nameCache.containsKey(itemId)) {
            return nameCache.get(itemId);
        }
        MapleData strings = getStringData(itemId);
        if (strings == null) {
            return null;
        }
        String ret = MapleDataTool.getString("name", strings, null);
        nameCache.put(itemId, ret);
        return ret;
    }

    public String getDesc(int itemId) {
        if (descCache.containsKey(itemId)) {
            return descCache.get(itemId);
        }
        MapleData strings = getStringData(itemId);
        if (strings == null) {
            return null;
        }
        String ret = MapleDataTool.getString("desc", strings, null);
        descCache.put(itemId, ret);
        return ret;
    }

    public String getMsg(int itemId) {
        if (msgCache.containsKey(itemId)) {
            return msgCache.get(itemId);
        }
        MapleData strings = getStringData(itemId);
        if (strings == null) {
            return null;
        }
        String ret = MapleDataTool.getString("msg", strings, null);
        msgCache.put(itemId, ret);
        return ret;
    }

    //设置装备的flag
    public boolean isDropRestricted(int itemId) {
        if (dropRestrictionCache.containsKey(itemId)) {
            return dropRestrictionCache.get(itemId);
        }
        MapleData data = getItemData(itemId);

        boolean bRestricted = MapleDataTool.getIntConvert("info/tradeBlock", data, 0) == 1;
        if (!bRestricted)
            bRestricted = MapleDataTool.getIntConvert("info/quest", data, 0) == 1;
        if(!bRestricted)
            bRestricted = MapleDataTool.getIntConvert("info/equipTradeBlock", data, 0) == 1; //永恒装备
        dropRestrictionCache.put(itemId, bRestricted);

        return bRestricted;
    }

    public boolean isPickupRestricted(int itemId) {
        if (pickupRestrictionCache.containsKey(itemId)) {
            return pickupRestrictionCache.get(itemId);
        }
        MapleData data = getItemData(itemId);
        boolean bRestricted = MapleDataTool.getIntConvert("info/only", data, 0) == 1;

        pickupRestrictionCache.put(itemId, bRestricted);
        return bRestricted;
    }

    public Map<String, Integer> getSkillStats(int itemId, double playerJob) {
        Map<String, Integer> ret = new LinkedHashMap<String, Integer>();
        MapleData item = getItemData(itemId);
        if (item == null) {
            return null;
        }
        MapleData info = item.getChildByPath("info");
        if (info == null) {
            return null;
        }
        for (MapleData data : info.getChildren()) {
            if (data.getName().startsWith("inc")) {
                ret.put(data.getName().substring(3), MapleDataTool.getIntConvert(data));
            }
        }
        ret.put("masterLevel", MapleDataTool.getInt("masterLevel", info, 0));
        ret.put("reqSkillLevel", MapleDataTool.getInt("reqSkillLevel", info, 0));
        ret.put("success", MapleDataTool.getInt("success", info, 0));

        MapleData skill = info.getChildByPath("skill");
        int curskill = 1;
        int size = skill.getChildren().size();
        for (int i = 0; i < size; i++) {
            curskill = MapleDataTool.getInt(Integer.toString(i), skill, 0);
            if (curskill == 0) // end - no more;
            {
                break;
            }
            double skillJob = Math.floor(curskill / 10000);
            if (skillJob == playerJob) {
                ret.put("skillid", curskill);
                break;
            }
        }

        if (ret.get("skillid") == null) {
            ret.put("skillid", 0);
        }
        return ret;
    }

    public List<Integer> petsCanConsume(int itemId) {
        List<Integer> ret = new ArrayList<Integer>();
        MapleData data = getItemData(itemId);
        int curPetId = 0;
        int size = data.getChildren().size();
        for (int i = 0; i < size; i++) {
            curPetId = MapleDataTool.getInt("spec/" + Integer.toString(i), data, 0);
            if (curPetId == 0) {
                break;
            }
            ret.add(Integer.valueOf(curPetId));
        }
        return ret;
    }

    public boolean isQuestItem(int itemId) {
        if (isQuestItemCache.containsKey(itemId)) {
            return isQuestItemCache.get(itemId);
        }
        MapleData data = getItemData(itemId);
        boolean questItem = MapleDataTool.getIntConvert("info/quest", data, 0) == 1;
        isQuestItemCache.put(itemId, questItem);
        return questItem;
    }

    public boolean isMiniDungeonMap(int mapId) {
        switch (mapId) {
            case 100020000:
            case 105040304:
            case 105050100:
            case 221023400:
                return true;
            default:
                return false;
        }
    }

    public boolean isDragonItem(int itemId) {
        switch (itemId) {
            case 1372032:
            case 1312031:
            case 1412026:
            case 1302059:
            case 1442045:
            case 1402036:
            case 1432038:
            case 1422028:
            case 1472051:
            case 1472052:
            case 1332049:
            case 1332050:
            case 1322052:
            case 1452044:
            case 1462039:
            case 1382036:
                return true;
            default:
                return false;
        }
    }

    public static class SummonEntry {

        private int chance,  mobId;

        public SummonEntry(int a, int b) {
            this.mobId = a;
            this.chance = b;
        }

        public int getChance() {
            return chance;
        }

        public int getMobId() {
            return mobId;
        }
    }

    public boolean isKarmaAble(int itemId) {
        if (karmaCache.containsKey(itemId)) {
            return karmaCache.get(itemId);
        }
        MapleData data = getItemData(itemId);
        boolean bRestricted = MapleDataTool.getIntConvert("info/tradeAvailable", data, 0) > 0;
        karmaCache.put(itemId, bRestricted);
        return bRestricted;
    }

    public boolean isConsumeOnPickup(int itemId) {
        if (consumeOnPickupCache.containsKey(itemId)) {
            return consumeOnPickupCache.get(itemId);
        }

        MapleData data = getItemData(itemId);

        boolean consume = MapleDataTool.getIntConvert("spec/consumeOnPickup", data, 0) == 1 || MapleDataTool.getIntConvert("specEx/consumeOnPickup", data, 0) == 1;

        consumeOnPickupCache.put(itemId, consume);
        return consume;
    }

    private void loadCardIdData() {
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            ps = DatabaseConnection.getConnection().prepareStatement("SELECT cardid, mobid FROM monstercarddata");
            rs = ps.executeQuery();
            while (rs.next())
                monsterBookID.put(rs.getInt(1), rs.getInt(2));
        } catch (SQLException e) {
        } finally {
            try {
                if (rs != null)
                    rs.close();
                if (ps != null)
                    ps.close();
            } catch (SQLException e) {
            }
        }
    }

    public int getCardMobId(int id) {
        return monsterBookID.get(id);
    }

    public List<MapleFish> getFishReward(int itemId) {
        if (fishingCache.containsKey(itemId)) {
            return fishingCache.get(itemId);
        } else {
            List<MapleFish> rewards = new ArrayList<MapleFish>();
            MapleData data = getItemData(itemId);
            MapleData rewardData = data.getChildByPath("reward");
            for (MapleData child : rewardData.getChildren()) {
                int rewardItem = MapleDataTool.getInt("item", child, 0);
                int prob = MapleDataTool.getInt("prob", child, 0);
                int count = MapleDataTool.getInt("count", child, 0);
                String effect = MapleDataTool.getString("Effect", child, "");
                rewards.add(new MapleFish(rewardItem, prob, count, effect));
            }
            fishingCache.put(itemId, rewards);
            return rewards;
        }
    }

     
    public List<Pair<String, Integer>> getItemLevelupStats(int itemId, int level, boolean timeless) {
        //timeless 永恒
        List<Pair<String, Integer>> list = new LinkedList<Pair<String, Integer>>();
        MapleData data = getItemData(itemId); //获得该物品所有节点
        MapleData data1 = data.getChildByPath("info").getChildByPath("level");
        /*
        if ((timeless && level == 5) || (!timeless && level == 3)) {
            MapleData skilldata = data1.getChildByPath("case").getChildByPath("1").getChildByPath(timeless ? "6" : "4");
            if (skilldata != null) {
                int skillid;
                List<MapleData> skills = skilldata.getChildByPath("Skill").getChildren();
                    for (int i = 0; i < skills.size(); i++) {
                        skillid = MapleDataTool.getInt(skills.get(i).getChildByPath("id"));
                        System.out.println(skillid);
                        if (Math.random() < 0.1) 
                            list.add(new Pair<String, Integer>("Skill" + i, skillid));
                    }
            }
        }
        */
        if (data1 != null) { //判断装备是否存在level节点
            MapleData data2 = data1.getChildByPath("info").getChildByPath(Integer.toString(level)); //获取与装备的[道具等级]相应的节点
            if (data2 != null) {
                    for (MapleData da : data2.getChildren()) {
                        if (Math.random() < 0.9) {
                            if (da.getName().startsWith("incDEXMin")) {
                                list.add(new Pair<String, Integer>("incDEX", rand(MapleDataTool.getInt(da), MapleDataTool.getInt(data2.getChildByPath("incDEXMax")))));
                            } else if (da.getName().startsWith("incSTRMin")) {
                                list.add(new Pair<String, Integer>("incSTR", rand(MapleDataTool.getInt(da), MapleDataTool.getInt(data2.getChildByPath("incSTRMax")))));
                            } else if (da.getName().startsWith("incINTMin")) {
                                list.add(new Pair<String, Integer>("incINT", rand(MapleDataTool.getInt(da), MapleDataTool.getInt(data2.getChildByPath("incINTMax")))));
                            } else if (da.getName().startsWith("incLUKMin")) {
                                list.add(new Pair<String, Integer>("incLUK", rand(MapleDataTool.getInt(da), MapleDataTool.getInt(data2.getChildByPath("incLUKMax")))));
                            } else if (da.getName().startsWith("incMHPMin")) {
                                list.add(new Pair<String, Integer>("incMHP", rand(MapleDataTool.getInt(da), MapleDataTool.getInt(data2.getChildByPath("incMHPMax")))));
                            } else if (da.getName().startsWith("incMMPMin")) {
                                list.add(new Pair<String, Integer>("incMMP", rand(MapleDataTool.getInt(da), MapleDataTool.getInt(data2.getChildByPath("incMMPMax")))));
                            } else if (da.getName().startsWith("incPADMin")) {
                                list.add(new Pair<String, Integer>("incPAD", rand(MapleDataTool.getInt(da), MapleDataTool.getInt(data2.getChildByPath("incPADMax")))));
                            } else if (da.getName().startsWith("incMADMin")) {
                                list.add(new Pair<String, Integer>("incMAD", rand(MapleDataTool.getInt(da), MapleDataTool.getInt(data2.getChildByPath("incMADMax")))));
                            } else if (da.getName().startsWith("incPDDMin")) {
                                list.add(new Pair<String, Integer>("incPDD", rand(MapleDataTool.getInt(da), MapleDataTool.getInt(data2.getChildByPath("incPDDMax")))));
                            } else if (da.getName().startsWith("incMDDMin")) {
                                list.add(new Pair<String, Integer>("incMDD", rand(MapleDataTool.getInt(da), MapleDataTool.getInt(data2.getChildByPath("incMDDMax")))));
                            } else if (da.getName().startsWith("incACCMin")) {
                                list.add(new Pair<String, Integer>("incACC", rand(MapleDataTool.getInt(da), MapleDataTool.getInt(data2.getChildByPath("incACCMax")))));
                            } else if (da.getName().startsWith("incEVAMin")) {
                                list.add(new Pair<String, Integer>("incEVA", rand(MapleDataTool.getInt(da), MapleDataTool.getInt(data2.getChildByPath("incEVAMax")))));
                            } else if (da.getName().startsWith("incSpeedMin")) {
                                list.add(new Pair<String, Integer>("incSpeed", rand(MapleDataTool.getInt(da), MapleDataTool.getInt(data2.getChildByPath("incSpeedMax")))));
                            } else if (da.getName().startsWith("incJumpMin")) {
                                list.add(new Pair<String, Integer>("incJump", rand(MapleDataTool.getInt(da), MapleDataTool.getInt(data2.getChildByPath("incJumpMax")))));
                            }
                        }
                    }
                }
            }
        return list;
    }
        
    private static int rand(int lbound, int ubound) {
        return (int) ((Math.random() * (ubound - lbound + 1)) + lbound);
    }
    
    public int getMakeItemMinLevel(int itemId) { //获取结晶对应的最小等级 锻造用 暂时不用
        if (getMakeItemMinLevel.containsKey(itemId)) {
            return getMakeItemMinLevel.get(itemId);
        }
        MapleData item = getItemData(itemId);
        if (item == null) {
            return -1;
        }
        int pEntry = 0;
        MapleData pData = item.getChildByPath("info/lvMin");
        if (pData == null) {
            return -1;
        }
        pEntry = MapleDataTool.getInt(pData);
        getMakeItemMinLevel.put(itemId, pEntry);
        return pEntry;
    }
    
    public int getMakeItemMaxLevel(int itemId) { //获取结晶对应的最大等级 锻造用 暂时不用
        if (getMakeItemMaxLevel.containsKey(itemId)) {
            return getMakeItemMaxLevel.get(itemId);
        }
        MapleData item = getItemData(itemId);
        if (item == null) {
            return -1;
        }
        int pEntry = 0;
        MapleData pData = item.getChildByPath("info/lvMax");
        if (pData == null) {
            return -1;
        }
        pEntry = MapleDataTool.getInt(pData);
        getMakeItemMaxLevel.put(itemId, pEntry);
        return pEntry;
    }
    
    public int getItemLevel(int itemId) { //获取物品对应的等级 锻造怪物结晶用到
        if (getItemLevel.containsKey(itemId)) {
            return getItemLevel.get(itemId);
        }
        MapleData item = getItemData(itemId);
        if (item == null) {
            return -1;
        }
        int pEntry = 0;
        MapleData pData = item.getChildByPath("info/lv");
        if (pData == null) {
            return -1;
        }
        pEntry = MapleDataTool.getInt(pData);
        getItemLevel.put(itemId, pEntry);
        return pEntry;
    }
    
    public int getCrystalId(int itemid) { //输入扣除的itemid直接获得相应的怪物结晶 锻造用
        int itemid2 = 0; //遍历Item.wz/Etc/0426.img获得的id
        int itemid4 = 0; //要输出的itemid
        int itemlv = getItemLevel(itemid);
        if(itemlv > 0) {
        System.out.println("物品等级 :"+itemlv);
        int min = 0;
        int max = 0;
        MapleDataProvider dataProvider = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("net.sf.odinms.wzpath") + "/" + "Item.wz"));
        MapleData a = dataProvider.getData("Etc/0426.img");
        for (MapleData b : a.getChildren()) { //getChildren 子项名 04260000
            itemid2 = Integer.parseInt(b.getName()); //获取itemid
            if(!getAllCrystalId.contains(itemid2)) //如果没有储存到静态里 就遍历储存
                getAllCrystalId.add(itemid2); //储存结晶的itemid
            //System.out.println("遍历0426.img的itemid2: "+itemid2);
            if (!getCrystalId.containsKey(itemid2)) { //如果没有储存到静态里 就遍历储存
                for (MapleData c : b.getChildren()) { //info
                    for (MapleData d : c.getChildren()) { //lvMax lvMin
                        if(d.getName().equals("lvMin"))
                            min = MapleDataTool.getInt(d); //获取lvMin的值
                        else if(d.getName().equals("lvMax"))
                            max = MapleDataTool.getInt(d); //获取lvMax的值
                    }
                }
                getCrystalId.put(itemid2, new Pair<Integer, Integer>(min, max));
            }
        }
        
        for(int itemid3 : getAllCrystalId){ //把在前面遍历获得的itemid 再遍历回去 getAllCrystalId是储存所有结晶itemid的排列
            Pair<Integer, Integer> ret3 = getCrystalId.get(itemid3);//返回ret 即获得上面的List<Pair<Integer, Integer>>
                if(ret3.getLeft() <= itemlv && ret3.getRight() >= itemlv) { //[31,50] 大小2边都可取等号
                    itemid4 = itemid3;
                    break;
                }
        }
        System.out.println("获取的结晶ID :"+itemid4);
        }
        return itemid4;
    }
    
    private int getCrystalId2(int itemid) { //通过扣除的普通怪物掉落物品获取要得到的怪物结晶id[数组遍历]
        MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
        int[][] a = new int[9][3];
        int b, itemlv = ii.getItemLevel(itemid), i;
        
        for(i = 0; i < a.length; i++){ //运行完后i再递增
            b = 4260000 + i;
            a[i][0] = b;
            a[i][1] = ii.getMakeItemMinLevel(b);
            a[i][2] = ii.getMakeItemMaxLevel(b);
        }

        for(i = 0; i < a.length; i++){ //运行完后i再递增
            if(itemlv >= a[i][1] && itemlv <= a[i][2])
                return a[i][0];
        }
        return 0;
    }
    
    public void setCrystalInSql() { //遍历WZ把符合锻造结晶的物品加入Sql表里
        int itemid = 0; //遍历Item.wz/Etc/0400.img获得的id
        MapleDataProvider dataProvider = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("net.sf.odinms.wzpath") + "/" + "Item.wz"));
        MapleData a = dataProvider.getData("Etc/0400.img");
        List<Integer> ret = new ArrayList<Integer>(); //储存所有0400.img的itemid
        for (MapleData b : a.getChildren()) { //getChildren 子项名 04000000
            itemid = Integer.parseInt(b.getName()); //获取itemid
            //System.out.println("遍历0400.img的itemid: "+itemid);
            ret.add(itemid);
        }
        int crystalid;
        try {
        Connection con = DatabaseConnection.getConnection();
        PreparedStatement ps = con.prepareStatement("INSERT INTO makertcrystaldata (itemid, crystalid) VALUES (?, ?)");
        for(int ret2 : ret) {
            crystalid = getCrystalId(ret2);
            if(crystalid > 0) {
                ps.setInt(1, ret2);
                ps.setInt(2, crystalid);
                ps.executeUpdate();
            }   
        }
        ps.close(); //循环结束再关表
        } catch (SQLException se) {
            log.error("结晶储存进SQL出错", se);
        }
    }
    
    public void setCashShopInfoInSql() { //遍历WZ把商城的物品的数据加入Sql表里
            MapleDataProvider dataProvider = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("net.sf.odinms.wzpath") + "/" + "Etc.wz"));
            MapleData a = dataProvider.getData("Commodity.img");
            int size = a.getChildren().size();
            Connection con = null;
            PreparedStatement ps = null;
	try { 
            System.out.println("Commodity.img总项数 ："+size);
            int i = 0;
            int SN = 0;
            int ItemId = 0;
            int Count = 0;
            int Price = 0;
            int Period = 0;
            int Gender = 0;
            int Priority = 0;
            int Bonus = 0;
            int PbCash = 0;
            int PbPoint = 0;
            int PbGift = 0;
            int Class2 = 0;
            int MaplePoint = 0;
            int Meso = 0;
            int OnSale = 0;
            con = DatabaseConnection.getConnection();
            ps = con.prepareStatement("INSERT INTO cashshopcheck (SN, itemId, count, price, period, gender, priority, bonus, pbCash, pbPoint, pbGift, class, maplePoint, meso, onSale) "
                    + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
            for (MapleData b : a.getChildren()) { //getChildren 子项名 0 1 10 100 1000 1001
                i += 1;
                for(MapleData c : b.getChildren()){ 
                    //SN, itemId, count, price, period, gender, priority, bonus, pbCash, pbPoint, pbGift, class2, maplePoint, meso，onSale
                    //没有写class 而且的class2的原因是因为会关键字冲突 没办法
                        if(c.getName().equals("SN")) {
                            SN = MapleDataTool.getInt(c);
                            //System.out.println("SN码 ："+SN);
                        } else if(c.getName().equals("ItemId"))
                            ItemId = MapleDataTool.getInt(c);
                        else if(c.getName().equals("Count"))
                            Count = MapleDataTool.getInt(c);
                        else if(c.getName().equals("Price"))
                            Price = MapleDataTool.getInt(c);
                        else if(c.getName().equals("Period"))
                            Period = MapleDataTool.getInt(c);
                        else if(c.getName().equals("Gender"))
                            Gender = MapleDataTool.getInt(c);
                        else if(c.getName().equals("Priority"))
                            Priority = MapleDataTool.getInt(c);
                        else if(c.getName().equals("Bonus"))
                            Bonus = MapleDataTool.getInt(c);
                        else if(c.getName().equals("PbCash"))
                            PbCash = MapleDataTool.getInt(c);
                        else if(c.getName().equals("PbPoint"))
                            PbPoint = MapleDataTool.getInt(c);
                        else if(c.getName().equals("PbGift"))
                            PbGift = MapleDataTool.getInt(c);
                        else if(c.getName().equals("Class"))
                            Class2 = MapleDataTool.getInt(c);
                        else if(c.getName().equals("MaplePoint"))
                            MaplePoint = MapleDataTool.getInt(c);
                        else if(c.getName().equals("Meso"))
                            Meso = MapleDataTool.getInt(c);
                        else if(c.getName().equals("OnSale"))
                            OnSale = MapleDataTool.getInt(c);
                }
                ps.setInt(1, SN);
                ps.setInt(2, ItemId);
                ps.setInt(3, Count);
                ps.setInt(4, Price);
                ps.setInt(5, Period);
                ps.setInt(6, Gender);
                ps.setInt(7, Priority);
                ps.setInt(8, Bonus);
                ps.setInt(9, PbCash);
                ps.setInt(10, PbPoint);
                ps.setInt(11, PbGift);
                ps.setInt(12, Class2);
                ps.setInt(13, MaplePoint);
                ps.setInt(14, Meso);
                ps.setInt(15, OnSale);
                ps.executeUpdate();
            }
            System.out.println("xml总项数 ："+i);
        } catch (SQLException ex) {
            log.error("商城xml储存进SQL出错", ex);
        } finally { //无论前面的SQL语句有没错 都可以执行finally里的语句
            if(ps != null)
                try {
                    ps.close();
                } catch (SQLException ex) {
                    log.error("商城SQL close出错", ex);
                }
        }
    }
    
    public void setMakeItemInfoInSql() { //遍历WZ把锻造的物品需要的数据加入Sql表里
            MapleDataProvider dataProvider = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("net.sf.odinms.wzpath") + "/" + "Etc.wz"));
            MapleData a = dataProvider.getData("ItemMake.img");
            Connection con = null;
            PreparedStatement ps = null;
            int i = 1;
            try {
                con = DatabaseConnection.getConnection();
            for (MapleData b : a.getChildren()) { //getChildren 子项名 0 1 2 4 8 16
                int type = Integer.parseInt(b.getName()); //属于哪个大类
                System.out.println("遍历节点: "+ type);
                for(MapleData c : b.getChildren()){ //itemid 01032062
                    int itemid = Integer.parseInt(c.getName()); //获取锻造要获得的itemid
                    if(Integer.parseInt(c.getName()) == 1072362) 
                        //这货 0_item 节点有问题 用HR打开会显示[未将对象引用设置到对象的实例]
                        continue;
                    System.out.println("正在遍历的itemid: "+itemid);
                    System.out.println("对应的序号: "+i);
                    i += 1;
                    //System.out.println("遍历ItemMake.img的itemid: "+itemid);
                    int quantity = 0;
                    int req_meso = 0;
                    int req_level = 0;
                    int req_maker_level = 0;
                    int tuc = 0;
                    int req_item = 0;
                    int req_equip = 0;
                    int catalyst = 0;
                    for (MapleData d : c.getChildren()) { //各属性节点
                        if(d.getName().equals("itemNum")) //需要扣除的数量 和 reqItem reqEquip对应 这2个节点不会同时存在 不用担心冲突
                            quantity = MapleDataTool.getInt(d);
                        else if(d.getName().equals("meso"))
                            req_meso = MapleDataTool.getInt(d);
                        else if(d.getName().equals("reqLevel"))
                            req_level = MapleDataTool.getInt(d);
                        else if(d.getName().equals("reqSkillLevel"))
                            req_maker_level = MapleDataTool.getInt(d);
                        else if(d.getName().equals("tuc")) //随机增加的砸卷次数上限
                            tuc = MapleDataTool.getInt(d);
                        else if(d.getName().equals("reqItem")) //需要的额外其他栏的物品
                            req_item = MapleDataTool.getInt(d);
                        else if(d.getName().equals("reqEquip")) //需要的额外装备物品
                            req_equip = MapleDataTool.getInt(d);
                        else if(d.getName().equals("catalyst")) //催化剂
                            catalyst = MapleDataTool.getInt(d);
                        else if(d.getName().equals("recipe")) { //需要额外材料
                            int req_item2 = 0; //这个是makerrecipedata表里的req_item
                            int count = 0;
                            for(MapleData e : d.getChildren()) { //0 1
                                for(MapleData f : e.getChildren()) { //count item
                                    if(f.getName().equals("count"))
                                        count = MapleDataTool.getInt(f);
                                    else if(f.getName().equals("item"))
                                        req_item2 = MapleDataTool.getInt(f);
                                }
                                    ps = con.prepareStatement("INSERT INTO makerrecipedata (itemid, req_item, count) VALUES (?, ?, ?)");
                                    ps.setInt(1, itemid);
                                    ps.setInt(2, req_item2);
                                    ps.setInt(3, count);
                                    ps.executeUpdate();
                            }
                        } //recipe
                    }
                    ps = con.prepareStatement("INSERT INTO makercreatedata (type, itemid, req_level, req_maker_level, req_meso, req_item, req_equip, catalyst, quantity, tuc) "
                            + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
                    ps.setInt(1, type);
                    ps.setInt(2, itemid);
                    ps.setInt(3, req_level);
                    ps.setInt(4, req_maker_level);
                    ps.setInt(5, req_meso);
                    ps.setInt(6, req_item);
                    ps.setInt(7, req_equip);
                    ps.setInt(8, catalyst);
                    ps.setInt(9, quantity);
                    ps.setInt(10, tuc);
                    ps.executeUpdate();
                } // itemid 遍历完
            } //所有遍历完
            } catch (SQLException e) {
                log.error("makeitem储存进SQL出错1", e);
            } finally { //无论前面的SQL语句有没错 都可以执行finally里的语句
                if (ps != null) 
                    try {
                        ps.close();
                    } catch (SQLException ex) {
                        log.error("makeitem储存进SQL出错2", ex);
                    }
            } //finally
    }
    
    public Point getMistItemLt(int itemId) { //获取物品的lt节点 Mist类物品 0528.img
        MapleData item = getItemData(itemId);
        Point pData = (Point) item.getChildByPath("info/lt").getData();
        return pData;
    }
    
    public Point getMistItemRb(int itemId) { //获取物品的rb节点 Mist类物品 0528.img
        MapleData item = getItemData(itemId);
        Point pData = (Point) item.getChildByPath("info/rb").getData();
        return pData;
    }
       
    //潜能附加卷
/*    public IItem potentialScrollEquipWithId(IItem equip, int scrollId) {
            Equip nEquip = (Equip) equip;
            double generator = Math.ceil(Math.random() * 100.0);
            boolean success = false;
            switch (scrollId) {
                case 2049400: {
                    if (generator <= 90) {
                        success = true;
                    }
                    break;
                }
                case 2049401: {
                    if (generator <= 70) {
                        success = true;
                    }
                    break;
                }
                default: {
                    return null;
                }
            }
            if (success) 
                nEquip.setIdentify((byte) 1);
            return equip; //return null是意味着装备消失了
    }*/

    public final IItem potentialScrollEquipWithId(IItem equip, int scrollId) {
        if ((equip instanceof Equip)) {
            Equip nEquip = (Equip) equip;
            int rate = scrollId == 2049400 ? 90 : 70;
            if (Randomizer.nextInt(100) <= rate) {
                switch (scrollId) {
                    case 2049400:
                    case 2049401:
                        nEquip.setIdentify((byte) 1);
                }
            } else {
                return null;
            }
        }
        return equip;
    }
    
    //放大镜处理
    public IItem MagniflerEquipWithId(IItem equip) {
            int count = 0;
            Equip nEquip = (Equip) equip;
            boolean isFirst = false;
            int oldPotentialLevel = nEquip.getIdentified();
            double a = Math.ceil(Math.random() * 50.0);
            if (oldPotentialLevel == 5) { //B级
                if (a >= 45) {
                    //90%几率升A级
                    nEquip.setIdentify((byte) 6);
                }
            } else if (oldPotentialLevel == 6) { //A级
                if (a == 50) {
                    //1%几率升S级
                    nEquip.setIdentify((byte) 7);
                }
            } else if (oldPotentialLevel == 7) { //S级
                nEquip.setIdentify((byte) 7);
            } else {
                //第一次鉴定
                isFirst = true;
                if(a == 50)
                    nEquip.setIdentify((byte) 7); //S级
                else if (a >=45)
                    nEquip.setIdentify((byte) 6); //A级
                else
                    nEquip.setIdentify((byte) 5); //B级
                count = (int) (2 + Math.random() * (2 - 1 + 1));
                for (int i = 1; i <= count; i++) {
                    nEquip.setPotential(i, randomPotentiaStat(1, nEquip.getItemId(), nEquip.getLevel()));
                }
            }
            if(!isFirst){
                //不是第一次的话就重设潜能
                //第一次的话在上面的判断中已经重新设置了
                for (int i = 0; i < 3; i++) {
                    if (nEquip.getPotential(i) != 0) {
                        count++;
                    }
                }
                for (int i = 1; i <= count; i++) {
                    nEquip.setPotential(i, randomPotentiaStat(nEquip.getIdentify(), nEquip.getItemId(), nEquip.getLevel()));
                }
            }
        return equip;
    }

    //随机产生潜能
    private int randomPotentiaStat(int oldPotentiaLevel, int itemId, byte itemLevel) {
        int rndOne = 0;
        int rnd = Randomizer.nextInt(5);
        int[] tempOptionId = null;
        switch (oldPotentiaLevel) {
            case 1: { //如果是第一次
                int OptionId[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 901, 902, 903, 904, 905};
                tempOptionId = OptionId;
                break;
            }
            case 5: { //B级
                //产生 0 - 5 之间的随机整数
                if (rnd == 0) {
                    int OptionId[] = {10001, 10002, 10003, 10004, 10005, 10006, 10007, 10008, 10009, 10010, 10011, 10012, 10013, 10014};
                    tempOptionId = OptionId;
                } else if (rnd == 1) {
                    int OptionId[] = {10041, 10042, 10043, 10044, 10045, 10046, 10047, 10048};
                    tempOptionId = OptionId;
                } else if (rnd == 2) {
                    int OptionId[] = {10051, 10052, 10053, 10054, 10055};
                    tempOptionId = OptionId;
                } else if (rnd == 3) {
                    int OptionId[] = {10070, 10081, 10151, 10156, 10201, 10206, 10221, 10226, 10231, 10236, 10241, 10246, 10291};
                    tempOptionId = OptionId;
                } else if (rnd == 4) {
                    int OptionId[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 901, 902, 903, 904, 905, 10001, 10002, 10003, 10004, 10005, 10006, 10007, 10008, 10009, 10010, 10011, 10012, 10013, 10014, 10041, 10042, 10043, 10044, 10045, 10046, 10047, 10048, 10051, 10052, 10053, 10054, 10055, 10070, 10081, 10151, 10156, 10201, 10206, 10221, 10226, 10231, 10236, 10241, 10246, 10291};
                    tempOptionId = OptionId;
                }
                break;
            }
            case 6: { //A级
                if (rnd == 0) {
                    int OptionId[] = {10001, 10002, 10003, 10004, 10005, 10006, 10007, 10008, 10009, 10010, 10011, 10012, 10013, 10014, 20041, 20042, 20043, 20044, 20045, 20046, 20047, 20048};
                    tempOptionId = OptionId;
                } else if (rnd == 1) {
                    int OptionId[] = {10041, 10042, 10043, 10044, 10045, 10046, 10047, 10048, 20051, 20052, 20053, 20054, 20055};
                    tempOptionId = OptionId;
                } else if (rnd == 2) {
                    int OptionId[] = {10051, 10052, 10053, 10054, 10055, 20070, 20086, 20201, 20206, 20291, 20351, 20352, 20353, 20366, 20376, 20396, 20401, 20406, 20501, 20511, 20650, 20656};
                    tempOptionId = OptionId;
                } else if (rnd == 3) {
                    int OptionId[] = {10070, 10081, 10151, 10156, 10201, 10206, 10221, 10226, 10231, 10236, 10241, 10246, 10291, 20041, 20042, 20043, 20044, 20045, 20046, 20047, 20048, 20051, 20052, 20053, 20054, 20055, 20070, 20086, 20181, 20201, 20206, 20291, 20351, 20352, 20353, 20366, 20376, 20396, 20401, 20406, 20501, 20511, 20650, 20656};
                    tempOptionId = OptionId;
                } else if (rnd == 4) {
                    int OptionId[] = {20041, 20042, 20043, 20044, 20045, 20046, 20047, 20048, 20051, 20052, 20053, 20054, 20055, 20070, 20086,  20201, 20206, 20291, 20351, 20352, 20353, 20366, 20376, 20396, 20401, 20406, 20501, 20511, 20650, 20656, 20041, 20042, 20043, 20044, 20045, 20046, 20047, 20048, 20051, 20052, 20053, 20054, 20055, 20070, 20086, 20201, 20206, 20291, 20351, 20352, 20353, 20366, 20376, 20396, 20401, 20406, 20501, 20511, 20650, 20656};
                    tempOptionId = OptionId;
                }
                break;
            }
            case 7: { //S级
                rnd = Randomizer.nextInt(4);
                if (rnd == 0) {
                    int OptionId[] = {20041, 20042, 20043, 20044, 20045, 20046, 20047, 20048, 30041, 30042, 30043, 30044, 30045, 30046, 30047, 30048};
                    tempOptionId = OptionId;
                } else if (rnd == 1) {
                    int OptionId[] = {20051, 20052, 20053, 20054, 20055, 30051, 30052, 30053, 30054, 30055};
                    tempOptionId = OptionId;
                } else if (rnd == 2) {
                    int OptionId[] = {20070, 20086, 20201, 20206, 20291, 20351, 20352, 20353, 20366, 20376, 20396, 20401, 20406, 20501, 20511, 20650, 20656, 30070, 30086, 30106, 30107, 30291, 30356, 30357, 30366, 30371, 30376, 30501, 30511, 30551, 30601, 30602, 30650, 30656, 30701, 30702, 31001, 31002, 31003, 31004};
                    tempOptionId = OptionId;
                } else if (rnd == 3) {
                    int OptionId[] = {20406, 20501, 20511, 20650, 20656, 20041, 20042, 20043, 20044, 20045, 20046, 20047, 20048, 20051, 20052, 20053, 20054, 20055, 20070, 20086, 20201, 20206, 20291, 20351, 20352, 20353, 20366, 20376, 20396, 20401, 20406, 20501, 20511, 20650, 20656, 30041, 30042, 30043, 30044, 30045, 30046, 30047, 30048, 30051, 30052, 30053, 30054, 30055, 30070, 30086, 30106, 30107, 30291, 30356, 30357, 30366, 30371, 30376, 30501, 30511, 30551, 30601, 30602, 30650, 30656, 30701, 30702, 31001, 31002, 31003, 31004};
                    tempOptionId = OptionId;
                }
                break;
            }
        }
        rndOne = tempOptionId[(int) Math.floor(Math.random() * tempOptionId.length)];
        System.out.print("备选潜能数组: "+tempOptionId);
        System.out.println("潜能节点: "+rndOne);
        while(!potentiaCanGain(itemId, rndOne)) {
            System.out.println("潜能不符合条件 重新生成");
            return randomPotentiaStat(oldPotentiaLevel, itemId, itemLevel);
        }
        return rndOne;
    }
    
    public void setPotentialInSql() { //遍历WZ把潜能节点加入Sql表里
        int potentialId = 0; //遍历Item.wz/ItemOption.img获得的潜能id
        MapleDataProvider dataProvider = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("net.sf.odinms.wzpath") + "/" + "Item.wz"));
        MapleData a = dataProvider.getData("ItemOption.img");
        try {
        Connection con = DatabaseConnection.getConnection();
        PreparedStatement ps = con.prepareStatement("INSERT INTO potentialdata (potentialid, optionType, reqLevel) VALUES (?, ?, ?)");
        for (MapleData b : a.getChildren()) { //getChildren 子项名 000001 - 031004
            int optionType = 0;
            int reqLevel = 0;
            potentialId = Integer.parseInt(b.getName()); //获取潜能节点的id
            System.out.println("遍历ItemOption.img的PotentialId: "+potentialId);
            for (MapleData c : b.getChildren()) { //info level
                if(c.getName().equals("info")) {
                    for (MapleData d : c.getChildren()) { // optionType reqLevel
                        if(d.getName().equals("optionType")) 
                            optionType = MapleDataTool.getInt(d);
                        if(d.getName().equals("reqLevel")) 
                            reqLevel = MapleDataTool.getInt(d);
                    }
                }
                System.out.println("optionType: "+optionType);
                System.out.println("reqLevel: "+reqLevel);
            }
            getPotentialId.put(potentialId, new Pair<Integer, Integer>(optionType, reqLevel));
            ps.setInt(1, potentialId);
            ps.setInt(2, optionType);
            ps.setInt(3, reqLevel);
            ps.executeUpdate();
        }
        ps.close(); //循环结束再关表
        } catch (SQLException se) {
            log.error("潜能节点储存进SQL出错", se);
        }
    }
    
    public Pair<Integer, Integer> getPotentialAtXml(int potentialid) { //获取潜能节点相关属性
        Pair<Integer, Integer> stats = getPotentialId.get(potentialid);
        if(stats == null) {
        int potentialId = 0; //遍历Item.wz/ItemOption.img获得的潜能id
        MapleDataProvider dataProvider = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("net.sf.odinms.wzpath") + "/" + "Item.wz"));
        MapleData a = dataProvider.getData("ItemOption.img");
        for (MapleData b : a.getChildren()) { //getChildren 子项名 000001 - 031004
            int optionType = 0;
            int reqLevel = 0;
            potentialId = Integer.parseInt(b.getName()); //获取潜能节点的id
            for (MapleData c : b.getChildren()) { //info level
                if(c.getName().equals("info")) {
                    for (MapleData d : c.getChildren()) { // optionType reqLevel
                        if(d.getName().equals("optionType")) 
                            optionType = MapleDataTool.getInt(d);
                        if(d.getName().equals("reqLevel")) 
                            reqLevel = MapleDataTool.getInt(d);
                    }
                }
            }
            getPotentialId.put(potentialId, new Pair<Integer, Integer>(optionType, reqLevel));
        }
        }
        return stats;
    }

    public String CheckitemType(int itemId) {
        String cat = "null";
        if (itemId >= 1010000 && itemId < 1040000 || itemId >= 1122000 && itemId < 1143000) {
            cat = "Accessory";
        } else if (itemId >= 1000000 && itemId < 1010000) {
            cat = "Cap";
        } else if (itemId >= 1102000 && itemId < 1103000) {
            cat = "Cape";
        } else if (itemId >= 1040000 && itemId < 1050000) {
            cat = "Coat";
        } else if (itemId >= 1080000 && itemId < 1090000) {
            cat = "Glove";
        } else if (itemId >= 1050000 && itemId < 1060000) {
            cat = "Longcoat";
        } else if (itemId >= 1060000 && itemId < 1070000) {
            cat = "Pants";
        } else if (itemId >= 1070000 && itemId < 1080000) {
            cat = "Shoes";
        } else if (itemId >= 1300000 && itemId < 1800000) {
            cat = "Weapon";
        } else if (itemId >= 1032000 && itemId < 1033000) {
            cat = "Ear";
        } else if (itemId >= 1942000 && itemId < 1982000) { //龙神装备
            cat = "Dragon";
        } else if (itemId >= 1612000 && itemId < 1662000) { //机械师装备
            cat = "Mechanic";
        } else if (itemId >= 1662000 && itemId < 1682000) { //智能机械人装备
            cat = "Android";
        }
        return cat;
    }
    
    //检查装备是否能接受该潜能
    public boolean potentiaCanGain(int itemid, int potentiaId) {
        int itemLevel = getReqLevel(itemid);
        String type = CheckitemType(itemid);
        boolean a = type.equals("Weapon");
        boolean b = type.equals("Accessory");
        boolean c = type.equals("Cap");
        boolean d = type.equals("Cape");
        boolean e = type.equals("Coat");
        boolean f = type.equals("Glove");
        boolean g = type.equals("Longcoat");
        boolean h = type.equals("Pants");
        boolean i = type.equals("Shoes");
        boolean j = type.equals("Ear");
        boolean k = c || d || e || f || g || h || i;
        boolean l = e || h || g;
        boolean m = (e || g) && !h;
        /*
         * a 武器 [10]
         * !a 非武器 [11]
         * b 项链 
         * c 帽子 [51]
         * d 披风
         * e 上衣
         * f 手套 [54]
         * g 套服
         * h 裤裙
         * i 鞋子 [55]
         * j 耳环 [40]
         * k = c + d + e + f + g + h + i 上衣 裤裙 套服 帽子 披风 鞋子 手套 [20]
         * l = e + h + g 上衣 裤裙 套服 [52]
         * m = e + h 上衣 裤裙 不包括套服 [53]
         */
        switch(potentiaId){
            //10 武器
            case 11:
            case 12:
            case 10011:
            case 10012:
            case 10051:
            case 10052:
            case 10055:
            case 10070:
            case 10201:
            case 10206:
            case 10221:
            case 10226:
            case 10231:
            case 10236:
            case 10241:
            case 10246:
            case 10291:
            case 20051:
            case 20052:
            case 20055:
            case 20070:
            case 20201:
            case 20206:
            case 20291:
            case 30051:
            case 30052:
            case 30055:
            case 30070:
                if (a)
                    return true;
            case 30291://(50)
            case 30602://(50)
                if (a && itemLevel >= 50)
                    return true;
            case 30601://(60)
                if (a && itemLevel >= 60)
                    return true;
                //11 非武器
            case 13:
            case 14:
            case 10013:
            case 10014:
            case 10045:
            case 10046:
            case 10053:
            case 10054:
            case 20045:
            case 20046:
            case 20053:
            case 20054:
            case 30045:
            case 30046:
            case 30053:
            case 30054:
            case 30551:
                if (!a)
                    return true;
                //20 上衣 裤裙 套服 帽子 披风 鞋子 手套 不包括饰品
            case 20351:
            case 20352:
            case 20353:
                if (k)
                    return true;
            case 30356://(20)
                if (k && itemLevel >= 20)
                    return true;
            case 30357://(40)
                if (k && itemLevel >= 40)
                    return true;
                //40 耳环
            case 10151:
            case 10156:
                if (j)
                    return true;
                //51 帽子
            case 901:
            case 902:
            case 903:
            case 904:
            case 905:
                if (c) 
                    return true;
            case 30106://(30)
                if (c && itemLevel >= 30) 
                    return true;
            case 30107://(50)
                if (c && itemLevel >= 50)
                    return true;
            case 31002://(70)
                if (c&& itemLevel >= 70)
                    return true;
                //52 上衣 裤裙 套服
            case 30366:
            case 30371:
            case 20366:
                if (l)
                    return true;
            case 20396://(50级)
                if (l && itemLevel >= 50)
                    return true;
                //53 上衣 裤裙 不包括套服
            case 31004://(70)
                if (m && itemLevel >= 70)
                    return true;
                //54 手套
            case 20401:
            case 20406:
                if (f)
                    return true;
            case 30701: //(20)
                if (f && itemLevel >= 20)
                    return true;
            case 30702: //(40)
                if (f && itemLevel >= 40)
                    return true;
            case 31003: //(120)
                if (f && itemLevel >= 120)
                    return true;
                //55 鞋子
            case 9:
            case 10:
            case 10009:
            case 10010:
                if (i)
                    return true;
            case 31001://(70)
                if (i && itemLevel >= 70)
                    return true;
                /*
                 * =================
                 * 20181 潜在能力未知
                 * 20376 潜在能力未知
                 * 20501 潜在能力未知
                 * 20511 潜在能力未知
                 * 20650 潜在能力未知
                 * 20656 潜在能力未知
                 * 30501 潜在能力未知
                 * 30511 潜在能力未知
                 * 30650 潜在能力未知
                 * 30656 潜在能力未知
                 * =================
                 * //开始90
            case 20181:
            case 20376:
            case 30376:
                    return true;
            case 20656://(30)
                if (itemLevel >= 30)
                    return true;
            case 20501://(50)
            case 20511://(50)
            case 20650://(50)
            case 30501://(50)
            case 30511://(50)
            case 30650://(50)
            case 30656://(50)
                if (itemLevel >= 50)
                    return true;
                 */
        }
        return false;
    }
    
    //星级
    public IItem starScrollEquipWithId(IItem equip, int scrollId) {
        if ((equip instanceof Equip)) {
            Equip nEquip = (Equip) equip;
            int rate = 0;
            switch (nEquip.getStarlevel()) {
                case 0:
                    rate = scrollId == 2049300 ? 100 : 80;
                    break;
                case 1:
                    rate = scrollId == 2049300 ? 90 : 70;
                    break;
                case 2:
                    rate = scrollId == 2049300 ? 80 : 60;
                    break;
                case 3:
                    rate = scrollId == 2049300 ? 70 : 50;
                    break;
                case 4:
                    rate = scrollId == 2049300 ? 60 : 40;
                    break;
                case 5:
                    rate = scrollId == 2049300 ? 50 : 30;
                    break;
                case 6:
                    rate = scrollId == 2049300 ? 40 : 20;
                    break;
                case 7:
                    rate = scrollId == 2049300 ? 30 : 10;
                    break;
                case 8:
                    rate = scrollId == 2049300 ? 20 : 10;
                    break;
                default:
                    rate = scrollId == 2049300 ? 10 : 10;
            }

            if (Randomizer.nextInt(100) <= rate) {
                nEquip.setStarlevel((byte) (nEquip.getStarlevel() + 1));
                if (nEquip.getStr() > 0) {
                    nEquip.setStr((short) (nEquip.getStr() + Randomizer.nextInt(5)));
                }
                if (nEquip.getDex() > 0) {
                    nEquip.setDex((short) (nEquip.getDex() + Randomizer.nextInt(5)));
                }
                if (nEquip.getInt() > 0) {
                    nEquip.setInt((short) (nEquip.getInt() + Randomizer.nextInt(5)));
                }
                if (nEquip.getLuk() > 0) {
                    nEquip.setLuk((short) (nEquip.getLuk() + Randomizer.nextInt(5)));
                }
                if (nEquip.getWatk() > 0) {
                    nEquip.setWatk((short) (nEquip.getWatk() + Randomizer.nextInt(5)));
                }
                if (nEquip.getWdef() > 0) {
                    nEquip.setWdef((short) (nEquip.getWdef() + Randomizer.nextInt(5)));
                }
                if (nEquip.getMatk() > 0) {
                    nEquip.setMatk((short) (nEquip.getMatk() + Randomizer.nextInt(5)));
                }
                if (nEquip.getMdef() > 0) {
                    nEquip.setMdef((short) (nEquip.getMdef() + Randomizer.nextInt(5)));
                }
                if (nEquip.getAcc() > 0) {
                    nEquip.setAcc((short) (nEquip.getAcc() + Randomizer.nextInt(5)));
                }
                if (nEquip.getAvoid() > 0) {
                    nEquip.setAvoid((short) (nEquip.getAvoid() + Randomizer.nextInt(5)));
                }
                if (nEquip.getSpeed() > 0) {
                    nEquip.setSpeed((short) (nEquip.getSpeed() + Randomizer.nextInt(5)));
                }
                if (nEquip.getJump() > 0) {
                    nEquip.setJump((short) (nEquip.getJump() + Randomizer.nextInt(5)));
                }
                if (nEquip.getHp() > 0) {
                    nEquip.setHp((short) (nEquip.getHp() + Randomizer.nextInt(5)));
                }
                if (nEquip.getMp() > 0) {
                    nEquip.setMp((short) (nEquip.getMp() + Randomizer.nextInt(5)));
                }
            } else {
                return null;
            }
        }
        return equip;
    }

    public void setMakeItemInfoToSql() { //遍历WZ把锻造的物品需要的数据加入Sql表里
            MapleDataProvider dataProvider = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("net.sf.odinms.wzpath") + "/" + "Item.wz" + "/" + "Consume"));
            MapleData a = dataProvider.getData("0251.img");
            Connection con = null;
            PreparedStatement ps = null;
            int i = 1;
            try {
                con = DatabaseConnection.getConnection();
            for (MapleData b : a.getChildren()) { //getChildren 子项名 0 1 2 4 8 16
                int type = Integer.parseInt(b.getName()); //属于哪个大类
                System.out.println("遍历节点: "+ type);
                for(MapleData c : b.getChildren()){ //itemid 01032062
                    int itemid = Integer.parseInt(c.getName()); //获取锻造要获得的itemid
                    System.out.println("正在遍历的itemid: "+itemid);
                    System.out.println("对应的序号: "+i);
                    i += 1;
                    //System.out.println("遍历ItemMake.img的itemid: "+itemid);
                    int quantity = 0;
                    int req_meso = 0;
                    int req_level = 0;
                    int req_maker_level = 0;
                    int tuc = 0;
                    int req_item = 0;
                    int req_equip = 0;
                    int catalyst = 0;
                    for (MapleData d : c.getChildren()) { //各属性节点
                        if(d.getName().equals("itemNum")) //需要扣除的数量 和 reqItem reqEquip对应 这2个节点不会同时存在 不用担心冲突
                            quantity = MapleDataTool.getInt(d);
                        else if(d.getName().equals("meso"))
                            req_meso = MapleDataTool.getInt(d);
                        else if(d.getName().equals("reqLevel"))
                            req_level = MapleDataTool.getInt(d);
                        else if(d.getName().equals("reqSkillLevel"))
                            req_maker_level = MapleDataTool.getInt(d);
                        else if(d.getName().equals("tuc")) //随机增加的砸卷次数上限
                            tuc = MapleDataTool.getInt(d);
                        else if(d.getName().equals("reqItem")) //需要的额外其他栏的物品
                            req_item = MapleDataTool.getInt(d);
                        else if(d.getName().equals("reqEquip")) //需要的额外装备物品
                            req_equip = MapleDataTool.getInt(d);
                        else if(d.getName().equals("catalyst")) //催化剂
                            catalyst = MapleDataTool.getInt(d);
                        else if(d.getName().equals("recipe")) { //需要额外材料
                            int req_item2 = 0; //这个是makerrecipedata表里的req_item
                            int count = 0;
                            for(MapleData e : d.getChildren()) { //0 1
                                for(MapleData f : e.getChildren()) { //count item
                                    if(f.getName().equals("count"))
                                        count = MapleDataTool.getInt(f);
                                    else if(f.getName().equals("item"))
                                        req_item2 = MapleDataTool.getInt(f);
                                }
                                    ps = con.prepareStatement("INSERT INTO makerrecipedata (itemid, req_item, count) VALUES (?, ?, ?)");
                                    ps.setInt(1, itemid);
                                    ps.setInt(2, req_item2);
                                    ps.setInt(3, count);
                                    ps.executeUpdate();
                            }
                        } //recipe
                    }
                    ps = con.prepareStatement("INSERT INTO makercreatedata (type, itemid, req_level, req_maker_level, req_meso, req_item, req_equip, catalyst, quantity, tuc) "
                            + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
                    ps.setInt(1, type);
                    ps.setInt(2, itemid);
                    ps.setInt(3, req_level);
                    ps.setInt(4, req_maker_level);
                    ps.setInt(5, req_meso);
                    ps.setInt(6, req_item);
                    ps.setInt(7, req_equip);
                    ps.setInt(8, catalyst);
                    ps.setInt(9, quantity);
                    ps.setInt(10, tuc);
                    ps.executeUpdate();
                } // itemid 遍历完
            } //所有遍历完
            } catch (SQLException e) {
                log.error("makeitem储存进SQL出错1", e);
            } finally { //无论前面的SQL语句有没错 都可以执行finally里的语句
                if (ps != null)
                    try {
                        ps.close();
                    } catch (SQLException ex) {
                        log.error("makeitem储存进SQL出错2", ex);
                    }
            } //finally
    }
}